/**
 * Copyright (C) 2009 Matteo Merli <mm@merlimat.org>
 * 
 * $Id: Main.java 20 2009-01-12 14:52:47Z matteo.merli $
 * $URL: http://pxl-lang.googlecode.com/svn/trunk/src/main/java/pxl/Main.java $
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *         http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package pxl;

import jline.ConsoleReader;
import jline.History;

import org.antlr.runtime.ANTLRFileStream;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;

import pxl.errors.ArithmeticError;
import pxl.errors.PxlException;
import pxl.errors.SyntaxError;
import pxl.grammar.classes.PxlLexer;
import pxl.grammar.classes.PxlParser;
import pxl.grammar.classes.PxlTreeWalker;
import pxl.types.None;
import pxl.types.PxlObject;
import pxl.types.PxlString;

public class Main
{

    public static void main( String[] args ) throws Exception
    {
        try
        {

            if ( args.length > 0 )
            {
                for ( String element : args )
                {
                    System.exit( doFile( element ) );
                }
            }
            else
            {
                doInteractive();
            }

        }
        catch ( Exception e )
        {
            System.err.println( "Exception: " + e );
            e.printStackTrace( System.err );
        }
    }

    public static class MyLexer extends PxlLexer
    {
        public MyLexer( CharStream lexer )
        {
            super( lexer );
        }

        public Token nextToken()
        {
            startPos = getCharPositionInLine();
            return super.nextToken();
        }
    }

    public static int doFile( String filename ) throws Exception
    {

        CharStream stream = null;
        CommonTokenStream tokens = null;
        PxlLexer lexer = null;
        PxlParser parser = null;

        try
        {

            try
            {
                stream = new ANTLRFileStream( filename );
                lexer = new MyLexer( stream );
                tokens = new CommonTokenStream( lexer );
                tokens.discardOffChannelTokens( true );
                PxlTokenSource indentedSource = new PxlTokenSource( tokens );
                tokens = new CommonTokenStream( indentedSource );

                parser = new PxlParser( tokens );

                Context ctx = Context.getInstance();
                ctx.push( new Scope( filename, GlobalScope.getInstance() ) );
                ctx.put( "__file__", new PxlString( filename ) );

                // ////////////////
                PxlParser.file_input_return ret = parser.file_input();
                int errors = parser.getNumberOfSyntaxErrors();
                if ( errors > 0 )
                    System.out.println( "Syntax error: " + errors );

                CommonTree tree = (CommonTree) ret.getTree();
                if ( tree != null )
                    System.out.println( "@@ " + tree.toStringTree() + " @@" );

                CommonTreeNodeStream treeStream = new CommonTreeNodeStream(
                        tree );
                PxlTreeWalker walker = new PxlTreeWalker( treeStream );
                walker.file_input();

                return 0;
            }
            catch ( ArithmeticException ae )
            {
                throw new ArithmeticError( ae.getMessage() );
            }

        }
        catch ( PxlException e )
        {

            // Print Pxl Stack trace
            // System.err.println( "Filename: " + parser.getFilename() );

            System.err.println( "Traceback: " );
            for ( Scope scope : Context.getInstance().getStackTrace() )
            {
                System.err.println( "    at '" + scope.getName() + "'" );
            }

            System.err.println( e );
        }
        catch ( Exception e )
        {
            System.err.println( "Parser exception: " + e );
            e.printStackTrace();
        }

        return -1;
    }

    public static void doInteractive() throws Exception
    {
        ConsoleReader reader = new ConsoleReader();
        reader.setHistory( new History() );

        CharStream stream = null;
        CommonTokenStream tokens = null;
        PxlLexer lexer = null;
        PxlParser parser = null;

        Scope scope = new Scope( "<stdin>", GlobalScope.getInstance() );
        Context.getInstance().push( scope );

        while ( true )
        {
            try
            {
                String line = reader.readLine( ">>> " );
                if ( line == null )
                    break;

                stream = new ANTLRStringStream( line + '\n' );
                lexer = new MyLexer( stream );
                tokens = new CommonTokenStream( lexer );
                tokens.discardOffChannelTokens( true );
                PxlTokenSource indentedSource = new PxlTokenSource( tokens );
                tokens = new CommonTokenStream( indentedSource );

                parser = new PxlParser( tokens );

                PxlParser.single_input_return ret = parser.single_input();
                int errors = parser.getNumberOfSyntaxErrors();
                if ( errors > 0 )
                    throw new SyntaxError();

                CommonTree tree = (CommonTree) ret.getTree();
                if ( tree != null )
                    System.out.println( "@@ " + tree.toStringTree() + " @@" );
                else
                    System.out.println( "tree == null" );

                CommonTreeNodeStream treeStream = new CommonTreeNodeStream(
                        tree );
                PxlTreeWalker walker = new PxlTreeWalker( treeStream );
                PxlObject res = walker.interactive_input();

                if ( res != null && res != None.instance() )
                    System.out.println( res.__repr__().toString() );

            }
            catch ( PxlException pe )
            {
                System.err.println( "Traceback: " );
                for ( Scope s : Context.getInstance().getStackTrace() )
                {
                    System.err.println( "    at '" + s.getName() + "'" );
                }

                System.err.println( pe );

            }
            catch ( Exception e )
            {
                System.err.println( "Exception: " + e );
                e.printStackTrace();
                System.exit( -1 );
            }
        }

        System.out.println();
    }

}
